home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-08-19 | 18.9 KB | 639 lines | [TEXT/CWIE] |
- /*************************************************************************************
- #
- # TGraphicCollection.cp
- #
- #
- # The TGraphicCollection class is a group of related TGraphic objects. Essentially,
- # the API for this class mimics the TGraphic class very closely, except that all of
- # the routines in TGraphicCollection pass in an index to which TGraphic object is being
- # referred to.
- #
- # Because this class relies so heavily on TGraphic, we share all of TGraphic's
- # limitations. In fact, any of the routines used to prepare drawing in TGraphic are
- # used without modification, since they apply to ALL TGraphic objects, regardless of
- # if they are in a collection or not.
- #
- # Note that this class isn't currently intended to be subclassed, so all of the methods
- # are non-virtual. This might change if at some point we determine we need to create
- # a subclass.#
- #
- # Author: Timothy Carroll
- # Apple Developer Technical Support
- # timc@apple.com
- #
- # Modification History:
- #
- # 6/1/96 TMC Initial Release
- #
- # Copyright © 1996 Apple Computer, Inc., All Rights Reserved
- #
- #
- # You may incorporate this sample code into your applications without
- # restriction, though the sample code has been provided "AS IS" and the
- # responsibility for its operation is 100% yours. However, what you are
- # not permitted to do is to redistribute the source as "DSC Sample Code"
- # after having made changes. If you're going to re-distribute the source,
- # we require that you make it clear in the source that the code was
- # descended from Apple Sample Code, but that you've made changes.
- #
- *************************************************************************************/
-
- #include <Memory.h>
- #include <Resources.h>
-
- #include "TGraphicCollection.h"
-
- /****************************************************************************************************
-
- Internal Declarations
-
- We will hold the list of created TGraphicCollectionObjects in a handle. This handle is
- automatically created the first time we load a TGraphicCollection and is deallocated when
- the list is empty.
-
- All of the allocation and deallocation is handled by the static NewCollection call.
-
- NewCollection has a few utility routines it calls on to manage the handle. Mainly they do
- the searching, insertion and deletion from the list.
- ****************************************************************************************************/
-
- static Handle gGraphicCollectionList = NULL;
- static unsigned long gNumberItemsInList = 0;
-
-
-
- static OSErr InsertCollectionIntoList (TGraphicCollection *theCollection, UInt32 index);
- static OSErr DeleteCollectionFromList (UInt32 index);
- static OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index);
-
- /****************************************************************************************************
- InsertCollectionIntoList
-
- This routine creates the handle if necessary, and otherwise inserts the TGraphicCollection
- into the list at the index location given.
-
- Assumptions:
- theCollection must be a legitimate TGraphicCollection -- no NULL parameters.
- index must be no more than 1 larger than gNumberItemsInList. ?????
- ****************************************************************************************************/
-
- OSErr InsertCollectionIntoList (TGraphicCollection *theCollection, UInt32 index)
- {
- OSErr theErr = noErr;
-
- #if qDebugging
- if (index > gNumberItemsInList)
- SIGNAL_ERROR ("\pAttempting to insert collection at invalid index")
- if (theCollection == NULL)
- SIGNAL_ERROR ("\pAttempting to insert a null collection into the list")
-
- #endif
-
- if (gGraphicCollectionList == NULL)
- {
- gNumberItemsInList = 1;
-
- gGraphicCollectionList = NewHandleClear (sizeof (TGraphicCollection *));
- theErr = MemError();
-
- FAIL_OSERR (theErr, "\pCouldn't allocate a new handle of information")
- FAIL_NIL (gGraphicCollectionList, "\pCouldn't allocate a new handle of information")
-
- }
- else
- {
- gNumberItemsInList++;
- SetHandleSize(gGraphicCollectionList,gNumberItemsInList*sizeof(TGraphicCollection *));
-
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
- FAIL_NIL (gGraphicCollectionList, "\pCouldn't resize the list handle")
-
- // Shift the data to make room
- BlockMoveData( (*(TGraphicCollection ***)gGraphicCollectionList)+index,
- (*(TGraphicCollection ***)gGraphicCollectionList)+index+1,
- (gNumberItemsInList - index-1) * sizeof(TGraphicCollection *));
- }
-
- // finally, set the new object in place
- *((*(TGraphicCollection ***) gGraphicCollectionList)+index) = theCollection;
-
- return noErr;
-
- error:
-
-
- if (theErr == noErr)
- theErr = paramErr;
- return theErr;
- }
-
-
- /****************************************************************************************************
- DeleteCollectionFromList
-
- This routine removes the collection from the list and destroys it. If there are no more items
- in the list then we dispose of the handle.
-
- Assumptions:
- index must be within the list.
- ****************************************************************************************************/
- OSErr DeleteCollectionFromList (UInt32 index)
- {
- OSErr theErr;
-
- gNumberItemsInList--;
-
- // slide remaining elements up
-
- BlockMoveData( (*(TGraphicCollection ***)gGraphicCollectionList)+index+1,
- (*(TGraphicCollection ***)gGraphicCollectionList)+index,
- (gNumberItemsInList - index) * sizeof(TGraphicCollection *));
-
- // cut back the storage and dispose of the handle if we have no items left
-
-
- if (gNumberItemsInList> 0)
- {
- SetHandleSize((Handle) gGraphicCollectionList,gNumberItemsInList*sizeof(TGraphicCollection *));
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
- FAIL_NIL (gGraphicCollectionList, "\pCouldn't resize the list handle")
- }
-
- else
- {
- DisposeHandle (gGraphicCollectionList);
- gGraphicCollectionList = NULL;
- }
-
-
- return noErr;
- error:
-
-
- if (theErr == noErr)
- theErr = paramErr;
- return theErr;
- }
-
-
- /****************************************************************************************************
- SearchCollectionList
-
- This routine searches through the list and attempts to find an existing TGraphicCollection with
- that resID. If it finds one with that resID, then it returns the index to that collection and
- sets found to true. If it doesn't find that resource, then it sets found to false AND sets the
- index to where it should be inserted into the list.
- ****************************************************************************************************/
- OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index)
- {
- UInt32 low = 0;
- UInt32 high = gNumberItemsInList;
- UInt32 tempIndex;
- TGraphicCollection *theItem;
-
- OSErr theErr = noErr;
-
- *found = false;
-
- while (low < high)
- {
- tempIndex = (low+high) >> 1;
-
- theItem = (*(TGraphicCollection ***)gGraphicCollectionList)[tempIndex];
-
- FAIL_NIL (theItem, "\pBad TGraphic object")
-
- if (resID < theItem->GetResID())
- high = tempIndex; // element is below "high"
- else if (resID == theItem->GetResID())
- {
- *found = true;
- *index = tempIndex;
- return noErr;
- }
- else
- low = tempIndex+1; // element is above "low"
- }
-
- // use final calculations to put insert in the right place in the list
- *index = (low+high) >> 1;
- return noErr;
-
- error:
-
- if (theErr == noErr)
- theErr = paramErr;
- return theErr;
-
-
- }
- /****************************************************************************************************
- TGraphicCollection::NewCollection
-
- This routine merely uses the routines we created above to properly create and load
- the TGraphicCollections.
- ****************************************************************************************************/
- TGraphicCollection
- *TGraphicCollection::NewCollection (SInt16 resID)
- {
- unsigned long listIndex;
- Boolean tableAlreadyExists;
- TGraphicCollection *newCollection = NULL;
- OSErr theErr;
-
- theErr = SearchCollectionList (resID, &tableAlreadyExists, &listIndex);
- FAIL_OSERR(theErr,"\pCouldn't search the collection list in TGraphicCollection::NewCollection")
-
- if (tableAlreadyExists)
- {
- // find the existing collection and add 1 to the ref count.
- newCollection = (*(TGraphicCollection ***)gGraphicCollectionList)[listIndex];
- newCollection->AddReference();
- }
- else
- {
- // create a new collection
- newCollection = new TGraphicCollection(resID);
- theErr = newCollection->CreateCollection ();
- FAIL_OSERR(theErr,"\pCouldn't create new TGraphicCollection")
- theErr = InsertCollectionIntoList(newCollection, listIndex);
- FAIL_OSERR(theErr, "\pCouldn't add new TGraphicCollection to list")
- newCollection->AddReference();
- }
-
- return newCollection;
- error:
- if (newCollection != NULL)
- delete newCollection;
- return NULL;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::AddReference
- ****************************************************************************************************/
-
- void
- TGraphicCollection::AddReference (void)
- {
- fReferenceCount++;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::DisposeReference
- ****************************************************************************************************/
-
- void
- TGraphicCollection::DisposeReference (void)
- {
- fReferenceCount--;
- if (fReferenceCount == 0)
- {
- UInt32 listIndex;
- Boolean tableEntry;
- OSErr theErr;
-
- theErr = SearchCollectionList (fResID, &tableEntry, &listIndex);
-
- FAIL_OSERR (theErr, "\pFailed to search the CollectionList")
- FAIL_FALSE (tableEntry, "\pFailed to find an existing TGraphicCollection in list")
-
- theErr = DeleteCollectionFromList(listIndex);
- FAIL_OSERR (theErr, "\pFailed to delete Collection from the list")
-
- delete this;
- }
-
- error:
- return;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::TGraphicCollection
-
- The constructor. We just set the variables to some nice, clean values and return. The real
- work will be done in CreateCollection, which actually can return an OSERR
- ****************************************************************************************************/
-
- TGraphicCollection::TGraphicCollection (SInt16 resID)
- {
- fResID = resID;
- fReferenceCount = 0;
- fGraphics = NULL;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::~TGraphicCollection
-
- The destructor, which pushes all the work of destroying the data to a separate routine which
- also can return an OSErr.
- ****************************************************************************************************/
-
- TGraphicCollection::~TGraphicCollection (void)
- {
- if (fGraphics != NULL)
- {
- OSErr theErr = DestroyCollection();
- FAIL_OSERR (theErr, "\pFailed to destroy the TGraphicCollection data")
- }
-
- error:
- return;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::CreateCollection
-
- This routine uses the resource number we passed into the contructor to load the TGraphicCollection
- from the 'SptA' resource we created for it. Note that we don't make any assumptions about
- the resource file being used, so the correct resource file already needs to be opened for this
- call to work.
- ****************************************************************************************************/
-
- OSErr TGraphicCollection::CreateCollection(void)
- {
- // Load the resource with our graphic collection's data. The format of this resource is basically
- // a 2 byte unsigned integer for the number of elements in the list, followed by the resource
- // ID for each of the TGraphic objects.
-
- UInt16 numGraphics;
- Handle collectionResource = Get1Resource ('SptA', fResID);
- OSErr theErr = ResError();
-
- FAIL_OSERR (theErr, "\pResource manager couldn't load the sprite resource")
- FAIL_NIL (collectionResource, "\pResource manager returned a null handle")
-
- // First things, find out the number of objects in the graphic. Then allocate
- // a handle to hold the TGraphic pointers.
-
- numGraphics = *((SInt16 *) (*collectionResource));
-
- // Later, we can change the format perhaps, and pass in a UInt32 so that we
- // don't have to convert it here. Saves an assembly instruction
-
- fNumberOfGraphics = numGraphics;
-
- fGraphics = NewHandleClear (fNumberOfGraphics * sizeof (TGraphic *));
-
- FAIL_NIL (fGraphics, "\pCouldn't allocate handle to hold the TGraphic objects")
-
- // Now we'll load each Graphic, one at a time, and add them to the handle, reporting
- // an error if any of them fail to load.
- UInt32 loop;
-
- HLock (fGraphics);
-
- for (loop = 0; loop < fNumberOfGraphics; loop++)
- {
- SInt16 graphicResID = *((SInt16 *)
- ((*collectionResource)+sizeof (UInt16)+sizeof (SInt16)*loop));
- // We've loaded the list of objects and their data. This list consists of a
- // 2 byte value (the number of graphics) followed by 2 byte values for each
- // graphic's resID. We'll load and enter them into the table in
- // order.
-
- TGraphic *theGraphic = TGraphic::NewGraphic (graphicResID);
- FAIL_NIL (theGraphic, "\pFailed to load graphic for collection")
-
- *((*(TGraphic ***)fGraphics)+loop) = theGraphic;
- }
-
- HUnlock (fGraphics);
- ReleaseResource (collectionResource);
-
- goto cleanup;
-
- error:
- if (theErr == noErr)
- theErr = paramErr;
-
- cleanup:
- // Note that we don't explictly call DestroyCollection here, since it will be called
- // when the object is destroyed, which should happen whenever we don't report noErr.
- if (collectionResource != NULL)
- ReleaseResource (collectionResource);
-
- // set a generic error code for those cases we don't have a real error code
-
-
- return theErr;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::DestroyCollection
-
- Throw away all of the objects that we're created. We do check for null TGraphic objects here,
- and properly skip null objects that might not have been finished from the create calls.
- ****************************************************************************************************/
-
- OSErr
- TGraphicCollection::DestroyCollection (void)
- {
- UInt32 loop;
-
- HLock (fGraphics);
- for (loop = 0; loop < fNumberOfGraphics ; loop++)
- {
- TGraphic *theGraphic = *((*(TGraphic ***)fGraphics)+loop);
- if (theGraphic != NULL)
- theGraphic->DisposeReference();
- }
- DisposeHandle (fGraphics);
- fGraphics = NULL;
-
- return noErr;
- }
-
-
-
-
-
- /****************************************************************************************************
- TGraphicCollection::LockCollection
-
- ****************************************************************************************************/
-
- OSErr
- TGraphicCollection::LockCollection (void)
- {
- UInt32 loop;
- OSErr theErr = noErr;
-
- MoveHHi (fGraphics);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't move fGraphics handle high")
- HLock (fGraphics);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't lock fGraphics handle")
-
- TGraphic **ptrToGraphics = (TGraphic **) *fGraphics;
-
- for (loop = 0; loop < fNumberOfGraphics ; loop++)
- {
- TGraphic *theGraphic = *ptrToGraphics++;
- theGraphic->LockGraphic();
- }
-
- return noErr;
-
- error:
- return theErr;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::LockCollection
-
- ****************************************************************************************************/
-
- OSErr
- TGraphicCollection::UnlockCollection (void)
- {
- UInt32 loop;
- OSErr theErr = noErr;
-
- // Should still be locked from the lock collection call. We should do some testing
- // to make sure we aren't locking and unlocking things multiple times here.
- TGraphic **ptrToGraphics = (TGraphic **) *fGraphics;
-
- for (loop = 0; loop < fNumberOfGraphics ; loop++)
- {
- TGraphic *theGraphic = *ptrToGraphics++;
- theGraphic->UnlockGraphic();
- }
-
- HUnlock (fGraphics);
- theErr = MemError();
- FAIL_OSERR (theErr, "\pCouldn't unlock fGraphics handle")
-
- return noErr;
-
- error:
- return theErr;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::GetBounds
-
- ****************************************************************************************************/
-
- Rect
- TGraphicCollection::GetBounds (UInt32 index)
- {
- TGraphic *theGraphic;
- #if qDebugging
- if (index >= fNumberOfGraphics)
- // We're outside of the bounds of the graphics table here. Debugger time! :-)
- SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
- #endif
-
- theGraphic = *((*(TGraphic ***)fGraphics)+index);
-
- #if qDebugging
- if (theGraphic == NULL)
- SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
- #endif
-
- return (theGraphic->GetBounds ());
-
- #if qDebugging
- error:
- Rect theRect = {0,0,0,0};
- return theRect;
- #endif
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::CopyImage
-
- ****************************************************************************************************/
-
- void
- TGraphicCollection::CopyImage (UInt32 index, SInt32 top, SInt32 left, Boolean useBackground)
- {
- TGraphic *theGraphic;
- #if qDebugging
- if (index >= fNumberOfGraphics)
- // We're outside of the bounds of the graphics table here. Debugger time! :-)
- SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
- #endif
-
- theGraphic = *((*(TGraphic ***)fGraphics)+index);
-
- #if qDebugging
- if (theGraphic == NULL)
- SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
- #endif
-
- theGraphic->CopyImage(top, left, useBackground);
-
- error:
- return;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::HitTest
-
- ****************************************************************************************************/
-
- Boolean
- TGraphicCollection::HitTest (UInt32 index, SInt32 v, SInt32 h)
- {
- TGraphic *theGraphic;
- #if qDebugging
- if (index >= fNumberOfGraphics)
- // We're outside of the bounds of the graphics table here. Debugger time! :-)
- SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
- #endif
-
- theGraphic = *((*(TGraphic ***)fGraphics)+index);
-
- #if qDebugging
- if (theGraphic == NULL)
- SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
- #endif
-
- return theGraphic->HitTest (v, h);
-
- error:
- return false;
- }
-
-
- /****************************************************************************************************
- TGraphicCollection::GetGraphicObject
-
- ****************************************************************************************************/
-
- TGraphic
- *TGraphicCollection::GetTGraphic (UInt32 index)
- {
- TGraphic *theGraphic;
- #if qDebugging
- if (index >= fNumberOfGraphics)
- // We're outside of the bounds of the graphics table here. Debugger time! :-)
- SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
- #endif
-
- theGraphic = *((*(TGraphic ***)fGraphics)+index);
- #if qDebugging
- if (theGraphic == NULL)
- SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
- #endif
-
- return theGraphic;
-
- error:
-
- return NULL;
- }